import { MaxResponse } from '@/types/axios.d'
import axios, { type AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios'
import NProgress from '@/plugins/nprogress'
import { AxiosOptions, InterceptorsOption } from '@/types/axios'
import AbortAxios from './abortAxios'

class Axios {
    private instance: AxiosInstance
    private options: AxiosOptions
    private interceptorsOption: InterceptorsOption | undefined

    constructor(config: AxiosOptions) {
        this.instance = axios.create(config)
        this.options = config
        this.interceptorsOption = config.interceptorsOption
        this.interceptors()
    }

    private interceptors() {
        if (!this.interceptorsOption) return

        const {
            requestResolve,
            requestReject,
            responseReject,
            responseResolve
        } = this.interceptorsOption
        const abortAxios = new AbortAxios()

        this.instance.interceptors.request.use((config) => {
            const abortRepetitiveRequest = (config as AxiosOptions).abortRepetitiveRequest ?? this.options.abortRepetitiveRequest
            abortRepetitiveRequest && abortAxios.addPending(config as AxiosOptions)
            return requestResolve ? requestResolve(config) : config
        }, requestReject ?? undefined)

        this.instance.interceptors.response.use(response => {
            response && abortAxios.removePending(response.config as AxiosOptions)
            response = responseResolve ? responseResolve(response) : response
            return response.data
        }, (err: AxiosError) => {
            return responseReject ? responseReject(this.instance, err) : err
        })
    }

    // private requestInterceptor() {
    //     this.instance.interceptors.request.use(config => {
    //         const admin = useAdmin()
    //         admin.getToken && (config.headers['Authorization'] = `Bearer ${admin.getToken}`)
    //         return config
    //     }, err => Promise.reject(err))
    // }

    // private responseInterceptor() {
    //     this.instance.interceptors.response.use(response => {
    //         const admin = useAdmin()
    //         if (response.headers['New-Token']) {
    //             admin.setToken(response.headers['New-Token'], response.headers['New-Expires-In'])
    //         }
    //         return response.data
    //     })
    // }

    public request<T, D = MaxResponse<T>>(config: AxiosRequestConfig) {
        NProgress.start()
        return new Promise(async (resolve, reject) => {
            try {
                const r = await this.instance.request(config) as D
                resolve(r)
            } catch (err) {
                reject(err)
            } finally {
                NProgress.done()
            }
        }) as Promise<D>
    }

    public get<T = any>(config: AxiosRequestConfig) {
        return this.request<T>({ ...config, method: 'GET' })
    }
    public post<T = any>(config: AxiosRequestConfig) {
        return this.request<T>({ ...config, method: 'POST' })
    }
    public put<T = any>(config: AxiosRequestConfig) {
        return this.request<T>({ ...config, method: 'PUT' })
    }
    public delete<T = any>(config: AxiosRequestConfig) {
        return this.request<T>({ ...config, method: 'DELETE' })
    }
}

export default Axios
